#!/usr/bin/env python

import os
import urllib
import json

from  datetime import datetime

from google.appengine.api import users
from google.appengine.ext import ndb
from google.appengine.ext import db

import jinja2
import webapp2
from Crypto.Hash import SHA512
from Crypto.Random import random

from baseClasses import BaseRequestHandler

JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__), 'markup')),
    extensions=['jinja2.ext.autoescape'],
    autoescape=True)


####################################################################################################
# Page Handlers

class Login(BaseRequestHandler):
    def get(self):
        template = JINJA_ENVIRONMENT.get_template('user/login.html')
        self.response.write(template.render(self.template_values))
        
    def is_valid_user(self, email, password):
        is_valid_user = False
        # retrieve user record (by username) 
        #user_query = User.query(ancestor=user_key()).order(-User.created_date)
        #user_list = user_query.fetch(10)
        query = User.query(User.user_name == email.lower())
        result = query.fetch()
        
        if len(result) <= 0:
            # if not exists, return false
            return is_valid_user
        
        # if exists, validate salt+password hash
        rec = result[0] 
        hasher = SHA512.new()
        hasher.update(rec.password_salt + password)
        is_valid_user = hasher.hexdigest() == rec.password_hash
        
        return is_valid_user
        
    def post(self):
        template = JINJA_ENVIRONMENT.get_template('user/login.html')
        
        #user.email = self.request.get('input_email')
        #user.first_name = self.request.get('input_first_name')
        #user.last_name = self.request.get('button_submit')
        #self.response.write("<p>{0}</p>".format(self.request.get('button_submit')))
        #self.response.write("<p>{0}</p>".format(self.request.get('input_email')))
        #self.response.write("<p>{0}</p>".format(self.request.get('input_password')))
        #self.response.write("<p>{0}</p>".format(self.request.get('checkbox_remember_me')))
        #input_email = self.request.get('input_email')
        #input_password = self.request.get('input_password')
        #checkbox_remember_me = self.request.get('checkbox_remember_me')
        #query = User.query(User.user_name == input_email.lower())
        #result = query.fetch() 
        #self.response.write(query)
        #self.response.write(result)
        #self.response.write("<p>{0}</p>".format(query))
        #self.response.write("<p>{0}</p>".format(result))
        #self.response.write("<p>{0}</p>".format(len(result)))
        #self.response.write("<p>{0}</p>".format(result[0]))
        
        # Get form values
        input_email = self.request.get('input_email')
        input_password = self.request.get('input_password')
        checkbox_remember_me = self.request.get('checkbox_remember_me')
        
        # Validate user credentials
        if self.is_valid_user(input_email, input_password):
            self.session["ACCOUNT_ID"] = input_email
            if self.request.GET.has_key('dst'):
                self.redirect(self.request.GET['dst'])
            else:
                self.response.write("NOT exists")
                self.redirect('/')

            #self.response.write("<p>{0}</p>".format("IS VALID USER"))
            #self.response.set_cookie('AUTH_SESS', 'get_user_login', max_age=360, path='/')
            #self.response.set_cookie('AUTH_ROLE', 'get_user_login', max_age=360, path='/')
            # self.response.write("<p>path: " + self.request.path + "</p>")
            # self.response.write("<p>path_info: " + self.request.path_info  + "</p>")
            # self.response.write("<p>path_url: " + self.request.path_url + "</p>")
            # self.response.write("<p>path_qs: " + self.request.path_qs + "</p>")
            # self.response.write("<p>application_url: " + self.request.application_url + "</p>")
            # self.response.write("<p>host_url: " + self.request.host_url + "</p>")
            # self.response.write("<p>path_url: " + self.request.path_url + "</p>")
            # #self.response.write("<p>relative_url: " + self.request.relative_url + "</p>")
            # self.response.write("<p>url: " + self.request.url + "</p>")
            # self.response.write("<p>query: " + self.request.query + "</p>")
            # self.response.write("<p>query_string: " + self.request.query_string + "</p>")
            
            # for x in self.request.GET.items():
            #     self.response.write(x)
            #self.response.write(str(dir(self.request.GET)))
            
            
            #self.response.write("<p>str_queryvars: " + self.request.str_queryvars + "</p>")
            
            #self.response.write("<p>queryvars: " + self.request.queryvars + "</p>")
            # if self.request.query["asd"]:
            #     self.response.write("no asd query string")
            # else:
            #     self.response.write("nhave asd query string")
            
        else:
            self.response.write("<p>{0}</p>".format("INVALID USER"))
            self.template_values["Error"] = {
                'Title' : "Error",
                'Message': "Invalid user credentials."
            }
            self.response.write(template.render(self.template_values))
            # self.template_values['input_email'] = input_email
            # self.template_values['input_password'] = input_password
            # self.template_values['checkbox_remember_me'] = checkbox_remember_me
            # self.template_values["ERROR"] = True
            # self.template_values["ERROR_TITLE"] = "Invalid user credentials."
            # self.template_values["ERROR_MESSAGE"] = "Invalid user credentials."


class Index(BaseRequestHandler):
    def get(self):
        template = JINJA_ENVIRONMENT.get_template('user_index.html')
        self.response.set_cookie('page', 'get_user_index', max_age=360, path='/')
        
        #user_name = self.request.get('user_name', DEFAULT_GUESTBOOK_NAME)

        # Ancestor Queries, as shown here, are strongly consistent
        # with the High Replication Datastore. Queries that span
        # entity groups are eventually consistent. If we omitted the
        # ancestor from this query there would be a slight chance that
        # Greeting that had just been written would not show up in a
        # query.
        user_query = User.query(
            ancestor=user_key()).order(-User.created_date)
        user_list = user_query.fetch(10)
        self.template_values["user_list"] = user_list
        
        self.response.write(template.render(self.template_values))
        

class AddUser(BaseRequestHandler):
    """Class:AddUser
    """
    
    def get(self):
        template = JINJA_ENVIRONMENT.get_template('user_add.html')
        self.response.set_cookie('page', 'get_user_add', max_age=360, path='/')
        self.response.write(template.render(self.template_values))
    
    
    def generate_password(self):
        password_salt = str(random.randint(0, 999999))
        hasher = SHA512.new()
        hasher.update(password_salt + 'P@ssw0rd')
        password_hash = hasher.hexdigest()
        return (password_salt, password_hash)
        
    
    def post(self):
        template = JINJA_ENVIRONMENT.get_template('user_add.html')
        self.response.set_cookie('page', 'post_user_add', max_age=360, path='/')

        user = User(parent=user_key())
        # if users.get_current_user():
        #     user.creator = users.get_current_user()
        
        # Get user input
        input_email = self.request.get('input_email')
        input_first_name = self.request.get('input_first_name')
        input_last_name = self.request.get('input_last_name')
        
        # Strip and validate user input
        input_email = input_email.strip()
        input_first_name = input_first_name.strip()
        input_last_name = input_last_name.strip()
        
        # Create entity
        user.email = input_email
        user.first_name = input_first_name
        user.last_name = input_last_name
        user.display_name = "{0}, {1}".format(input_first_name, input_last_name)
        user.user_name = input_email.lower()
        
        (user.password_salt, user.password_hash) = self.generate_password()
        
        user.creator = "UNKNOWN"
        user.created_date = datetime.utcnow()
        user.modifier = None
        user.modified_date = None
        
        user.put()
        self.redirect('/user/')
        
class EditUser(BaseRequestHandler):
    def get(self, *args, **kwargs):
        if len(args) > 0:
            entity_key = ndb.Key(urlsafe=args[0])
            result = entity_key.get()
            self.template_values["user"] = result
            
            template = JINJA_ENVIRONMENT.get_template('user_edit.html')
            self.response.set_cookie('page', 'get_user_edit', max_age=360, path='/')
            self.response.write(template.render(self.template_values))
        else:
            self.response.write('Record not found.')
        
    def post(self, *args, **kwargs):
        try:
            template = JINJA_ENVIRONMENT.get_template('user_add.html')
            self.response.set_cookie('page', 'post_user_add', max_age=360, path='/')
            
            entity_key = ndb.Key(urlsafe=self.request.get('user_key'))
            target_entity = entity_key.get()
            target_entity.email = self.request.get('input_email')
            target_entity.first_name = self.request.get('input_first_name')
            target_entity.last_name = self.request.get('input_last_name')
            if users.get_current_user():
                target_entity.modifier = users.get_current_user()
            target_entity.modified_date = datetime.utcnow()
            target_entity.put()
            self.redirect('/user/')
        except Exception, e:
            self.response.write("failed")
            self.response.write(e)
            
class DeleteUser(BaseRequestHandler):
    def get(self, *args, **kwargs):
        if len(args) > 0:
            #fetch
            entity_key = ndb.Key(urlsafe=args[0])
            result = entity_key.get()
            self.template_values["user"] = result
            
            template = JINJA_ENVIRONMENT.get_template('user_delete.html')
            self.response.set_cookie('page', 'get_user_delete', max_age=360, path='/')
            self.response.write(template.render(self.template_values))
        else:
            self.response.write('Record not found.')
        
    def post(self, *args, **kwargs):
        try:
            template = JINJA_ENVIRONMENT.get_template('user_add.html')
            self.response.set_cookie('page', 'post_user_add', max_age=360, path='/')
            
            entity_key = ndb.Key(urlsafe=self.request.get('user_key'))
            entity_key.delete()
            self.redirect('/user/')
        except Exception, e:
            self.response.write("failed")
            self.response.write(e)
        
class Index2(webapp2.RequestHandler):
    def get(self, *args, **kwargs):
        self.response.write(args)
        self.response.write(kwargs)
        self.response.write('Project List!')



####################################################################################################
# Models

def user_key(user_type_name='application_user'):
    """Constructs a Datastore key for a User entity.

    We use user_type_name as the key.
    """
    return ndb.Key('user_type', user_type_name)


class User(ndb.Model):
    email = ndb.StringProperty(indexed=False)
    first_name = ndb.StringProperty(indexed=False)
    last_name = ndb.StringProperty(indexed=False)
    display_name = ndb.StringProperty(indexed=False)
    user_name = ndb.StringProperty()
    
    password_salt = ndb.TextProperty()
    password_hash = ndb.TextProperty()
    
    creator = ndb.StringProperty()
    created_date = ndb.DateTimeProperty(auto_now_add=True)
    modifier = ndb.StringProperty()
    modified_date = ndb.DateTimeProperty(auto_now_add=False)
    
    

config = {}
config['webapp2_extras.sessions'] = {
    'secret_key': 'some-secret-key',
}

####################################################################################################
# Routing

"""ZX: 
    It is recommended that the routing urls have (?i) to make it case-insensitive.
    Routing urls should end with slash (/).
    If there's no slash, browser (eg Google Chrome) might treat it as a document 
    and perform search instead of routing it.
"""
app = webapp2.WSGIApplication([
    #(r'(?i)^/projects/(\w+)*$', ProjectsPageHandler),
    (r'(?i)^/user/$', Index),
    (r'(?i)^/user/login$', Login),
    (r'(?i)^/user/add$', AddUser),
    (r'(?i)^/user/edit/(.+)$', EditUser),
    (r'(?i)^/user/delete/(.+)$', DeleteUser)
], debug=True, config=config)


# Reference
# https://blog.abahgat.com/2013/01/07/user-authentication-with-webapp2-on-google-app-engine/